package com.chatplus.application.service.account.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chatplus.application.common.enumeration.UserStatusEnum;
import com.chatplus.application.common.exception.BadRequestException;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.dao.account.WechatUserDao;
import com.chatplus.application.domain.entity.account.UserEntity;
import com.chatplus.application.domain.entity.account.WechatUserEntity;
import com.chatplus.application.domain.response.WechatLoginQrResponse;
import com.chatplus.application.service.account.UserService;
import com.chatplus.application.service.account.WechatUserService;
import com.chatplus.application.service.wxmp.WeChatMpEventKeyHandler;
import com.chatplus.application.service.wxmp.builder.TextBuilder;
import com.chatplus.application.service.wxmp.impl.WeChatMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 微信小程序用户业务逻辑实现
 *
 * <p>Table: t_wechat_user - 微信小程序用户</p>
 *
 * @author developer
 * @see WechatUserEntity
 */
@Service
public class WechatUserServiceImpl extends ServiceImpl<WechatUserDao, WechatUserEntity> implements WechatUserService {
    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(WechatUserServiceImpl.class);
    private final WeChatMpService weChatMpService;
    private final UserService userService;
    private final RedissonClient redissonClient;

    public static final Integer EXPIRE_SECONDS = 10 * 60;

    public WechatUserServiceImpl(WeChatMpService weChatMpService
            , UserService userService
            , RedissonClient redissonClient) {
        this.weChatMpService = weChatMpService;
        this.userService = userService;
        this.redissonClient = redissonClient;
    }


    @Override
    public WechatLoginQrResponse getLoginQrCode() {
        try {
            WechatLoginQrResponse wechatLoginQrResponse = new WechatLoginQrResponse();
            String qrUuid = UUID.randomUUID().toString();
            WxMpQrCodeTicket wxMpQrCodeTicket = weChatMpService.getQrcodeService().qrCodeCreateTmpTicket(qrUuid, EXPIRE_SECONDS);
            String qrCodeUrl = weChatMpService.getQrcodeService().qrCodePictureUrl(wxMpQrCodeTicket.getTicket());
            String ticket = wxMpQrCodeTicket.getTicket();
            redissonClient.getBucket(ticket).set(-1L, Duration.ofSeconds(EXPIRE_SECONDS));
            wechatLoginQrResponse.setTicket(ticket);
            wechatLoginQrResponse.setCodeUrl(qrCodeUrl);
            weChatMpService.addHandler(qrUuid, new WeChatMpEventKeyHandler() {
                /**
                 * 扫码后调用该方法
                 * @param wxMpXmlMessage 扫码消息
                 * @param weChatUser 扫码用户
                 * @return 输出消息
                 */
                @Override
                public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, WechatUserEntity weChatUser) {
                    //用户扫描后触发该方法, 发送扫码成功的同时，将wsUuid与微信用户绑定在一起，用后面使用wsU
                    LOGGER.message("用户扫描二维码").context("openid", wxMpXmlMessage.getFromUser()).info();
                    String openid = wxMpXmlMessage.getFromUser();
                    if (openid == null) {
                        LOGGER.message("openid is null").error();
                    }
                    UserEntity userEntity = userService.getById(weChatUser.getUserId());
                    if (userEntity != null && userEntity.getStatus() == UserStatusEnum.OK) {
                        redissonClient.getBucket(ticket).set(userEntity.getId(), Duration.ofSeconds(EXPIRE_SECONDS));
                        // 登录操作
                        return new TextBuilder().build(String.format("登录成功，登录的用户为： %s", userEntity.getNickname()),
                                wxMpXmlMessage,
                                null);
                    } else {
                        return new TextBuilder().build("登录失败，原因：您尚未绑定微信用户，如有疑问，请留言或者联系管理员，我们会尽快回复您",
                                wxMpXmlMessage,
                                null);
                    }
                }
            });
            return wechatLoginQrResponse;
        } catch (Exception e) {
            LOGGER.message("获取登录二维码失败").exception(e).error();
        }
        return null;
    }


    @Override
    public WechatUserEntity getOneByOpenidAndAppId(String openId, String appId) {
        return getOne(new LambdaQueryWrapper<>(WechatUserEntity.class)
                .eq(WechatUserEntity::getOpenId, openId)
                .eq(WechatUserEntity::getAppId, appId)
                .last("limit 1"));
    }

    @Override
    public WechatLoginQrResponse generateBindQrCode(Long userId) {
        try {
            // 1. 生成用于回调的sceneStr，请将推送给微信，微信当推送带有sceneStr的二维码，用户扫码后微信则会把带有sceneStr的信息回推过来
            LOGGER.message("生成绑定二维码").context("userId", userId).info();
            UserEntity userEntity = userService.getById(userId);
            if (userEntity == null) {
                LOGGER.message("用户不存在").context("userId", userId).error();
                throw new BadRequestException("用户不存在");
            }
            final Map<String, String> variables = new HashMap<>();
            variables.put("userId", userEntity.getId().toString());
            String requestUrl = addParam("http:/localhost:8082/request/getQrCode", variables);
            System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2,SSLv3");
            RestTemplate restTemplate = new RestTemplate();
            String bindQrCode = restTemplate.getForObject(requestUrl, String.class, variables);
            WechatLoginQrResponse wechatLoginQrResponse = new WechatLoginQrResponse();
            wechatLoginQrResponse.setCodeUrl(bindQrCode);
            wechatLoginQrResponse.setTicket(userId.toString());
            return wechatLoginQrResponse;
        } catch (Exception e) {
            LOGGER.message("获取绑定二维码失败").exception(e).error();
            throw new BadRequestException("获取绑定二维码失败");
        }
    }

    @Override
    public WechatUserEntity getByUserId(Long userId) {
        return getOne(new LambdaQueryWrapper<>(WechatUserEntity.class)
                .eq(WechatUserEntity::getUserId, userId)
                .last("limit 1"));
    }

    public static String addParam(String url, Map<String, String> variables) {
        StringBuilder requestUrl = new StringBuilder(url);
        String symbol = "?";
        // 添加url参数格式
        for (Map.Entry<String, String> entry : variables.entrySet()) {
            requestUrl.append(symbol).append(entry.getKey()).append("={").append(entry.getKey()).append("}");
            symbol = "&";
        }
        return requestUrl.toString();
    }
}
